package websocket.piggy;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import cn.hutool.core.io.IoUtil;

public class PcmCovWavUtil {
    //录音的采样频率
    private static int audioRate = 16000;
    //录音的声道，单声道
    private static int audioChannel = 1;
    //量化的深度
    private static int audioFormat = 16;

    /**
     * pcm流 转 wav流
     */

    //添加Wav头部信息
    private static void addWaveFileHeader(OutputStream out, long totalAudioLen,
                                          long totalDataLen, long sampleRate,
                                          int channels, long byteRate) throws IOException {
        byte[] header = new byte[44];
        // RIFF 头表示
        header[0] = 'R';
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        //数据大小，数据大小，真正大小是添加了8bit
        header[4] = (byte) (totalDataLen & 0xff);
        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
        //wave格式
        header[8] = 'W';//WAVE
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        //fmt Chunk
        header[12] = 'f'; // 'fmt '
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        //数据大小
        header[16] = 16; // 4 bytes: size of 'fmt ' chunk
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        //编码方式 10H为PCM编码格式
        header[20] = 1; // format = 1
        header[21] = 0;
        //通道数
        header[22] = (byte) channels;
        header[23] = 0;
        //采样率，每个通道的播放速度
        header[24] = (byte) (sampleRate & 0xff);
        header[25] = (byte) ((sampleRate >> 8) & 0xff);
        header[26] = (byte) ((sampleRate >> 16) & 0xff);
        header[27] = (byte) ((sampleRate >> 24) & 0xff);
        //音频数据传送速率,采样率*通道数*采样深度/8
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        int tongDaoWei;
        if (audioChannel == 1) {
            tongDaoWei = 1;
        } else {
            tongDaoWei = 2;
        }
        // 确定系统一次要处理多少个这样字节的数据，确定缓冲区，通道数*采样位数
        header[32] = (byte) (16 / 8);
        if (audioFormat == 16) {
            header[32] = (byte) (tongDaoWei * 16 / 8);
        } else if (audioFormat == 8) {
            header[32] = (byte) (tongDaoWei * 8 / 8);
        }
        header[33] = 0;
        //每个样本的数据位数
        if (audioFormat == 16) {
            header[34] = 16;
        } else if (audioFormat == 8) {
            header[34] = 8;
        }

        header[35] = 0;
        //Data chunk
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (totalAudioLen & 0xff);
        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
        out.write(header, 0, 44);
    }

    public static void convertWaveFile(ByteArrayOutputStream byteArrayOutputStream, ByteArrayOutputStream tempStream) {
        long audioBytesLen = byteArrayOutputStream.size();
        long dataTotalLen = audioBytesLen + 36;;
        long rate = audioRate;
        int channels = audioChannel;

        long byteRate = 16L * audioRate * channels / 8;
        if (audioFormat == 16) {
            byteRate = 16L * audioRate * channels / 8;
        } else if (audioFormat == 8) {
            byteRate = 8L * audioRate * channels / 8;
        }

        try {
            addWaveFileHeader(tempStream, audioBytesLen, dataTotalLen, rate, channels, byteRate);
            tempStream.write(byteArrayOutputStream.toByteArray());
        } catch (Exception e) {
            try {
                tempStream.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
            e.printStackTrace();
        }
    }

    public static void generateWavFile(String filepath) throws IOException {
        byte[] fileBytes = Files.readAllBytes(Paths.get(filepath));
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byteArrayOutputStream.write(fileBytes);
        ByteArrayOutputStream tempStream = new ByteArrayOutputStream();
        convertWaveFile(byteArrayOutputStream, tempStream);
        FileOutputStream fileOutputStream = new FileOutputStream(filepath + ".wav");
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(tempStream.toByteArray());
        IoUtil.copy(byteArrayInputStream, fileOutputStream);
        fileOutputStream.flush();
        fileOutputStream.close();
    }


    public static void generateWavFile2(String filepath) throws IOException {
        byte[] fileBytes = Files.readAllBytes(Paths.get(filepath));
        byte[] bytes = AudioFormatConverter.pcmToWav(fileBytes);
        FileOutputStream fileOutputStream = new FileOutputStream(filepath + ".wav");
        fileOutputStream.write(bytes);
        fileOutputStream.close();
    }


    public static void addBytesToFile(String filePath, byte[] bytes) throws IOException {
        File file = new File(filePath);
        if(!file.exists()){
            boolean newFile = file.createNewFile();
        }
        try (FileOutputStream fos = new FileOutputStream(filePath,true)) {
            fos.write(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static byte[] createWavFromPcm(byte[] pcmData, int sampleRate, int channels, int bitsPerSample) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

        // 计算文件的相关参数
        int byteRate = sampleRate * channels * bitsPerSample / 8;
        int dataSize = pcmData.length;
        int chunkSize = 36 + dataSize; // 36 + PCM 数据大小

        // 写入 RIFF 标头
        byteArrayOutputStream.write("RIFF".getBytes()); // 4 字节
        writeInt(byteArrayOutputStream, chunkSize); // 文件大小 - 8 字节
        byteArrayOutputStream.write("WAVE".getBytes()); // 4 字节

        // 写入 fmt 块
        byteArrayOutputStream.write("fmt ".getBytes()); // 4 字节
        writeInt(byteArrayOutputStream, 16); // fmt 块的大小
        writeShort(byteArrayOutputStream, (short) 1); // 音频格式（1 表示 PCM）
        writeShort(byteArrayOutputStream, (short) channels); // 声道数
        writeInt(byteArrayOutputStream, sampleRate); // 采样率
        writeInt(byteArrayOutputStream, byteRate); // 每秒字节数
        writeShort(byteArrayOutputStream, (short) (channels * bitsPerSample / 8)); // 每个样本的字节数
        writeShort(byteArrayOutputStream, (short) bitsPerSample); // 位深度

        // 写入 data 块
        byteArrayOutputStream.write("data".getBytes()); // 4 字节
        writeInt(byteArrayOutputStream, dataSize); // 数据块大小
        byteArrayOutputStream.write(pcmData); // 写入 PCM 数据

        return byteArrayOutputStream.toByteArray();
    }

    private static void writeInt(ByteArrayOutputStream stream, int value) throws IOException {
        stream.write((value) & 0xFF);
        stream.write((value >> 8) & 0xFF);
        stream.write((value >> 16) & 0xFF);
        stream.write((value >> 24) & 0xFF);
    }

    private static void writeShort(ByteArrayOutputStream stream, short value) throws IOException {
        stream.write((value) & 0xFF);
        stream.write((value >> 8) & 0xFF);
    }


    public static void main(String[] args) throws IOException {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        byte [] bytes1 = {1,2,3,4,5,56,6};
        byteArrayOutputStream.write(bytes1);
        byte [] bytes2 = {2,3,57,6,7};
        byteArrayOutputStream.write(bytes2);
        byte[] byteArray = byteArrayOutputStream.toByteArray();
        System.out.println(Arrays.toString(byteArray));

        try {
            String filePath = "D:\\test\\output";
            File file = new File(filePath);
            if(file.exists()){
                boolean delete = file.delete();
                System.out.println(delete);
            }
            for(int i=0; i<4; i++){
                try (FileOutputStream fos = new FileOutputStream(filePath,true)) {
                    fos.write(bytes2);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            byte[] bytes = Files.readAllBytes(file.toPath());
            System.out.println(Arrays.toString(bytes));
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
